from fetch import IF
from decoder import ID, type
from execute import EX, ecall
from memory import MEM
from data_type import bit_64
from write_back import WB
from MMU import memory, MMU, load_instant
from register_file import registers_file
from elf_read import save_sections
from system import init
import sys

if len(sys.argv) > 1:
    filename = sys.argv[1]
else:
    filename = "arch-fib"

mem = memory(0x80000)
mmu = MMU(128, 128)
load_table, entry = save_sections(filename)
init(load_table)
load_instant(mem, mmu, load_table)


rf = registers_file()
wbW, rdW, jobW = bit_64(), 0, type()
wbM, addrM, contentM, rdM, jobM = bit_64(), bit_64(), bit_64(), 0, type()
jobE, rs1_rE, rs2_rE, immE, rs1E, rs2E, rdE, pcE, widthE = type(), bit_64(), bit_64(), bit_64(), 0, 0, 0, bit_64(), 0
instrD, widthD, pcD = 0, 0, bit_64()
pcF = bit_64(entry)

rf.ports_in(2, 0x40007ffe20)
call = ecall()

top = 0x4000800000 - 0x80000


while True:
#    print("PC = %x" % pcF.val)
#    if pcF.val == 0x102f0:
#        print("now")
    WB(wbW, rdW, jobW, rf)

    wbW, rdW, jobW = MEM(wbM, addrM, contentM, rdM, jobM, mem, mmu)

    if jobE.name == "ecall":
        call.update(rdM, wbM, jobM, rdW, wbW, jobW, rf)

    jump, pc_next, wbM, addrM, contentM, rdM, jobM = EX(jobE, rs1_rE, rs2_rE, immE, rdE, pcE, widthE, mem, mmu, call)

    if jump:
        flush = True
    else:
        flush = False

    rdE_pre, jobE_pre = rdE, jobE
    jobE, rs1_rE, rs2_rE, immE, rs1E, rs2E, rdE, pcE, widthE = ID(instrD, widthD, pcD, rf)

    if jobM.wb and rdM != 0 and rdM == rs1E:
        forward1 = 1  # from M
    elif jobW.wb and rdW != 0 and rdW == rs1E:
        forward1 = 2  # from W
    else:
        forward1 = 0

    if jobM.wb and rdM != 0 and rdM == rs2E:
        forward2 = 1  # from M
    elif jobW.wb and rdW != 0 and rdW == rs2E:
        forward2 = 2  # from W
    else:
        forward2 = 0

    if jobE_pre.do == 2 and (rdE_pre == rs1E or rdE_pre == rs2E):
        stall = True
    else:
        stall = False

    instrD_pre, widthD_pre, pcD_pre = instrD, widthD, pcD
    instrD, widthD, pcD = IF(pcF, mem, mmu)

    pcF_pre = pcF
    pcF = pc_next if jump else bit_64(pcF.val + 2 if widthD == 16 else pcF.val + 4)

    if forward1 == 1:
        rs1_rE = wbM
    elif forward1 == 2:
        rs1_rE = wbW

    if forward2 == 1:
        rs2_rE = wbM
    elif forward2 == 2:
        rs2_rE = wbW

    if stall:
        pcF = pcF_pre
        instrD, widthD, pcD = instrD_pre, widthD_pre, pcD_pre
        jobE, rs1_rE, rs2_rE, immE, rs1E, rs2E, rdE, pcE, widthE = type(), bit_64(), bit_64(), bit_64(), 0, 0, 0, bit_64(), 0
    elif flush:
        instrD, widthD, pcD = 0, 0, bit_64()
        jobE, rs1_rE, rs2_rE, immE, rs1E, rs2E, rdE, pcE, widthE = type(), bit_64(), bit_64(), bit_64(), 0, 0, 0, bit_64(), 0

#    print("=================================")
